package com.lx.encryption.plugin.util;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;


/**
 * @author liuzhiqiang
 * jar操作工具类
 */
public class JarUtils {

    /**
     * 加密密码
     */
    private String password;
    /**
     * 加密目录
     */
    private String[] packages;
    /**
     * 指定后缀的文件
     */
    private String[] suffix;
    /**
     * 指定文件
     */
    private String[] specifyFile;

    public JarUtils(String password, String[] packages, String[] suffix, String[] specifyFile) {
        this.password = password;
        this.packages = packages;
        this.suffix = suffix;
        this.specifyFile = specifyFile;
    }

    /**
     * 获取class运行的classes目录或所在的jar包目录
     *
     * @return 路径字符串
     */
    public static String getRootPath(String path) {
        if (path == null) {
            path = JarUtils.class.getResource("").getPath();
        }

        try {
            path = java.net.URLDecoder.decode(path, "utf-8");
        } catch (UnsupportedEncodingException e) {
        }

        if (path.startsWith("jar:") || path.startsWith("war:")) {
            path = path.substring(4);
        }
        if (path.startsWith("file:")) {
            path = path.substring(5);
        }

        //没解压的war包
        if (path.contains("*")) {
            return path.substring(0, path.indexOf("*"));
        }
        //war包解压后的WEB-INF
        else if (path.contains("WEB-INF")) {
            return path.substring(0, path.indexOf("WEB-INF"));
        }
        //jar
        else if (path.contains("!")) {
            return path.substring(0, path.indexOf("!"));
        }
        //普通jar/war
        else if (path.endsWith(".jar") || path.endsWith(".war")) {
            return path;
        }
        //no
        else if (path.contains("/classes/")) {
            return path.substring(0, path.indexOf("/classes/") + 9);
        }
        return null;
    }

    /**
     * 读取流
     *
     * @param inStream
     * @return 字节数组
     * @throws Exception
     */
    public byte[] readStream(InputStream inStream) throws Exception {
        ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        while ((len = inStream.read(buffer)) != -1) {
            outSteam.write(buffer, 0, len);
        }
        outSteam.close();
        inStream.close();
        return outSteam.toByteArray();
    }

    /**
     * 加密Jar包里的文件
     *
     * @param jarFilePath
     * @throws Exception
     */
    public void writeJarFile(String jarFilePath) throws Exception {

        //1、首先将原Jar包里的所有内容读取到内存里，用TreeMap保存
        JarFile jarFile = new JarFile(jarFilePath);
        //可以保持排列的顺序,所以用TreeMap 而不用HashMap
        TreeMap tm = new TreeMap();
        Enumeration es = jarFile.entries();
        while (es.hasMoreElements()) {
            Map<String, Object> map = new HashMap<>();
            JarEntry entry = (JarEntry) es.nextElement();
            map.put("entry", entry);

            String name = entry.getName();

            byte[] bytes = readStream(jarFile.getInputStream(entry));

            Boolean on = false;
            if (!StringUtils.endsWith(name, "/")) {
                // 文件
                String fileSuffix = name.split("\\.")[name.split("\\.").length - 1];
                for (String packagePath : packages) {
                    packagePath = packagePath.replaceAll("\\.", "\\/");
                    packagePath = "BOOT-INF/classes/" + packagePath;
                    if (StringUtils.contains(name, packagePath) && ArrayUtils.contains(suffix, fileSuffix)) {
                        on = true;
                    }
                }
                String fileName = name.split("/")[name.split("/").length - 1];
                if (ArrayUtils.contains(specifyFile, fileName)) {
                    on = true;
                }
            }

            if (on) {
                // 密文
                byte[] cipherText = DESUtil.encryptByte(password, bytes);
                map.put("bytes", cipherText);
                tm.put(name, map);
                System.out.println("加密文件[" + name + "]");
            } else {
                map.put("bytes", bytes);
                tm.put(name, map);
            }
        }

        JarOutputStream jos = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(jarFilePath)));
        Iterator it = tm.entrySet().iterator();

        //2、将TreeMap重新写到原jar里，如果TreeMap里已经有entryName文件那么覆盖，否则在最后添加
        while (it.hasNext()) {
            Map.Entry item = (Map.Entry) it.next();
            String name = (String) item.getKey();
            Map<String, Object> map = (Map<String, Object>) item.getValue();
            JarEntry entry = (JarEntry) map.get("entry");
            byte[] temp = (byte[]) map.get("bytes");
            JarEntry jarEntry = new JarEntry(name);
            jarEntry.setMethod(entry.getMethod());
            jarEntry.setSize(entry.getSize());
            jarEntry.setCrc(entry.getCrc());
            jos.putNextEntry(jarEntry);
            jos.write(temp, 0, temp.length);
        }
        jos.finish();
        jos.close();


    }

}
